package com.sghd.fight.module.game.service.room;

import com.sghd.common.utils.ManagedException;
import com.sghd.fight.module.game.config.LevelConfig;
import com.sghd.fight.module.game.core.Magic;
import com.sghd.fight.module.game.core.model.BattleSkill;
import com.sghd.fight.module.game.core.model.EliminateResult;
import com.sghd.fight.module.game.core.model.Unit;
import com.sghd.fight.module.game.event.PushEvent;
import com.sghd.fight.module.game.service.skill.ConfigService;
import com.sghd.fight.module.game.service.work.RoomRunner;
import com.sghd.fight.module.game.service.work.RoomTimer;
import com.sghd.fight.module.game.service.work.RoomWork;
import com.sghd.fight.net.SocketEnum;
import com.sghd.pojo.candy.fight.dto.SettleTo;
import com.sghd.pojo.fight.game.*;

import java.util.*;

/**
 * @author frank
 * @date 2018-10-22 17:22
 * @desc
 **/
public class PveRoom extends IRoom {

    private LevelConfig level;

    public PveRoom(long id, RoomType type, RoomTimer timer, ConfigService configService, LevelConfig level, long seed) {
        super(id, type, timer, configService, seed);
        this.level = level;
    }

    /**
     * 怪物行动
     */
    public void monsterTimer(Date now) {
        //TODO 怪物行动
        timer.addTimer(new RoomWork(this, new RoomRunner() {
            @Override
            public void run(Date now) {
                if (current instanceof Monster) {
                    if (isOver()) {
                        return;
                    }
                    Monster monster = (Monster) current;
                    if (level.getUnique() == 0) {
                        if (level.getCommon() == 0) {
                            monsterSkill(level.getAttackId());
                        } else {
                            monsterSkill(getSkillId(monster));
                        }
                    } else {
                        if (level.getUnique() == 1) {
                            logger.debug("当前回合", countRound);
                            if (countRound == 2) {
                                monsterSkill(10034);
                            } else if (countRound > 2) {
                                monsterSkill(level.getSeckillId());
                            } else {
                                throw new ManagedException(-3, "怪物行动异常");
                            }
                        } else if (level.getUnique() == 2) {
                            if (monster.getValue(UnitValue.HP) <= (monster.getValue(UnitValue.HP_MAX) * 0.3)) {
                                monsterSkill(level.getSeckillId());
                            } else {
                                monsterSkill(getSkillId(monster));
                            }
                        } else {
                            throw new ManagedException(-3, "怪物行动异常");
                        }
                    }
                } else {
                    monsterTimer(now);
                }
            }
        }, new Date(now.getTime() + 3000)));
    }

    /**
     * 获取monster行动的技能ID
     */
    private int getSkillId(Monster monster) {
        Integer skillId = monster.getWeight2Skill().getResult();
        if (monster.getSkill(skillId).isCanUse()) {
            return skillId;
        } else {
            return getSkillId(monster);
        }
    }

    /**
     * 怪兽执行技能
     */
    public void monsterSkill(int skillId) {
        if (current instanceof Monster) {
            Monster monster = (Monster) current;
            try {
                execute(current.getId(), skillId);
            } catch (ManagedException e) {
                logger.debug(e.getMessage());
                if (e.getCode() == 2) {
                    logger.debug("技能[{}]执行失败,改为执行普攻", skillId);
                    execute(current.getId(), level.getAttackId());
                }
            } catch (Exception e) {
                logger.debug("monster执行技能未知异常");
                e.printStackTrace();
            }
        }
        monsterTimer(new Date());
    }

    @Override
    public SettleTo getSettleTo(Collection<Long> playerIds, ExitReason reason) {
        //正常死亡
        if (reason == ExitReason.DEAD) {
            Player player = null;
            for (Unit unit : units.values()) {
                if (unit instanceof Player) {
                    player = (Player) unit;
                }
            }
            return SettleTo.valueOf(player.getId(), player.getValue(UnitValue.HP_MAX), player.getValue(UnitValue.HP),
                    0, level.getId().getBigLevelId(), level.getId().getLevelId(), countRound, reason);
        } else {//非正常结束
            Player player = null;
            for (Unit unit : units.values()) {
                if (unit instanceof Player) {
                    player = (Player) unit;
                }
            }
            return SettleTo.valueOf(player.getId(), player.getValue(UnitValue.HP_MAX), 0,
                    0, level.getId().getBigLevelId(), level.getId().getLevelId(), countRound, reason);
        }
    }

    @Override
    public void dead() {
        super.gameOver(ExitReason.DEAD);
    }

    @Override
    public void execute(long playerId, int skillId) {
        Unit unit = units.get(playerId);
        BattleSkill battleSkill = unit.getSkill(skillId);
        if (battleSkill == null) {
            throw new ManagedException(-1, "技能不存在");
        }
        //debuff导致技能无法使用
        if (unit.notUse()) {
            logger.debug("因为封魔无法使用技能 改为执行普通攻击");
            if (skillId != 10027) {
                throw new ManagedException(-1, "当前无法使用！");
            }
        }
        if (current.getId() != unit.getId()) {
            logger.debug("current[{}],player[{}]", current.getId(), playerId);
            throw new ManagedException(-1, "不是当前玩家回合！");
        }
        if (!battleSkill.canUse()) {
            throw new ManagedException(-2, "技能正在冷确中！");
        }
        Map<String, Object> ctx = new HashMap<>();
        SkillReport report = skilled(unit, skillId, ctx);
        //推送给客户端
        report.setDate(System.currentTimeMillis() + getConfig().getRoundTime());
        syncPost(PushEvent.NAME, PushEvent.valueOf(report, new ArrayList<>(units.keySet()), SocketEnum._EXECUTE_SKILL));
        super.execute(playerId, skillId);
    }

    public LevelConfig getLevel() {
        return level;
    }

    public void setLevel(LevelConfig level) {
        this.level = level;
    }

    @Override
    public RoomVo toVo() {
        RoomVo roomVo = new RoomVo();
        List<UnitVo> unitVos = new ArrayList<>();
        for (Unit unit : units.values()) {
            if (unit.getType() == UnitEnum.PLAYER) {
                unitVos.add(((Player) unit).toVo());
            }
            if (unit.getType() == UnitEnum.ROBOT) {
                unitVos.add(((Monster) unit).toVo());
            }
        }
        roomVo.setMagic_Max(Magic.magic_Max);
        roomVo.setPlayers(unitVos);
        roomVo.setSeed(chessBoard.getRandom().getSeed());
        Date now = new Date();
        long startTime = now.getTime() + getConfig().getRoundTime();
        roomVo.setStartTime(startTime);
        return roomVo;
    }

    @Override
    public void start() {
        if (state == BEGIN || isOver()) {
            return;
        }
        state = BEGIN;
        chessBoard.genarete();
        roundStart(new Date());
        monsterTimer(new Date());
    }

    @Override
    public void checkAndCollect(EliminateResult result, Unit unit) {
        super.checkRound(result, unit);
        if (unit.getType() == UnitEnum.PLAYER) {
            collect(result, unit);
        }
    }
}
